// Copyright 2024 ztlcloud.com
// leovs @2024.12.9

package types

import (
	"encoding/json"
	"errors"
	"regexp"
	"sync"
)

// LMap 自定义有序Map类型
type LMap[T any] struct {
	mux  sync.RWMutex
	keys []any
	vals []T
}

func (m *LMap[T]) Put(key any, val T) *LMap[T] {
	m.mux.Lock()
	defer m.mux.Unlock()

	if key == "" {
		return m
	}

	// 判断key是否已存在，存在则更新值
	if m.Set(key, val) {
		return m
	}

	m.keys = append(m.keys, key)
	m.vals = append(m.vals, val)
	return m
}

func (m *LMap[T]) Get(index int) *T {
	m.mux.Lock()
	defer m.mux.Unlock()
	if index < len(m.keys) {
		return &m.vals[index]
	}
	return nil
}

func (m *LMap[T]) Len() int {
	return len(m.keys)
}

func (m *LMap[T]) Keys() []any {
	return m.keys
}

func (m *LMap[T]) Values() []T {
	return m.vals
}

func (m *LMap[T]) Has(key any) bool {
	m.mux.RLock()
	defer m.mux.RUnlock()
	for _, v := range m.keys {
		if key == v {
			return true
		}
	}
	return false
}

func (m *LMap[T]) Set(k any, v T) bool {
	m.mux.Lock()
	defer m.mux.Unlock()
	for i, key := range m.keys {
		if k == key {
			m.vals[i] = v
			return true
		}
	}
	return false
}

func (m *LMap[T]) Remove(key any) {
	m.mux.Lock()
	defer m.mux.Unlock()
	for i, v := range m.keys {
		if key == v {
			m.keys = append(m.keys[:i], m.keys[i+1:]...)
			m.vals = append(m.vals[:i], m.vals[i+1:]...)
		}
	}
}

func (m *LMap[T]) Clear() {
	m.mux.Lock()
	defer m.mux.Unlock()
	m.keys = nil
	m.vals = nil
}

func (m *LMap[T]) Each(f func(key any, val T) bool) {
	m.mux.Lock()
	defer m.mux.Unlock()
	for i, v := range m.keys {
		if f(v, m.vals[i]) {
			break
		}
	}
}

func (m *LMap[T]) UnmarshalJSON(value []byte) error {
	var data map[string]T
	if err := json.Unmarshal(value, &data); err == nil {
		// 通过正则表达式匹配key值
		pattern := regexp.MustCompile(`"([^"]+)":`)
		match := pattern.FindAllStringSubmatch(string(value), -1)
		for _, v := range match {
			if v != nil && len(v) > 1 {
				m.Put(v[1], data[v[1]])
			}
		}
		return nil
	}
	return errors.New("failed to unmarshal Map value")
}

func (m *LMap[T]) MarshalJSON() ([]byte, error) {
	var data map[any]any
	for i, v := range m.keys {
		data[v] = m.vals[i]
	}
	return json.Marshal(data)
}

func (m *LMap[T]) String() string {
	m.mux.RLock()
	defer m.mux.RUnlock()
	if val, err := m.MarshalJSON(); err == nil {
		return string(val)
	}
	return ""
}
